using System;
using System.Collections;
using System.Diagnostics;
using System.Text;
using ActiproSoftware.SyntaxEditor.Addons.Simple.Ast;

namespace ActiproSoftware.SyntaxEditor.Addons.Simple.Ast {

	/// <summary>
	/// Provides the base class for an AST node.
	/// </summary>
	/// <remarks>
	/// <para>
	/// Each AST node has a single parent and optional children.
	/// The nodes may be navigated by parent to child or child to parent.
	/// When a node is created, it initially has no parent node.
	/// </para>
	/// <para>
	/// AST nodes implement the visitor pattern.
	/// </para>
	/// </remarks>
	public abstract class AstNode : ActiproSoftware.SyntaxEditor.AstNodeBase {

		private byte contextID;
		
		/// <summary>
		/// Gets the minimum context ID that should be used in your code for AST nodes inheriting this class.
		/// </summary>
		/// <remarks>
		/// Base all your context ID constants off of this value.
		/// </remarks>
		protected const byte AstNodeContextIDBase = AstNode.ContextIDBase;

		/////////////////////////////////////////////////////////////////////////////////////////////////////
		// OBJECT
		/////////////////////////////////////////////////////////////////////////////////////////////////////
		
		/// <summary>
		/// Initializes a new instance of the <c>AstNode</c> class. 
		/// </summary>
		public AstNode() {}

		/// <summary>
		/// Initializes a new instance of the <c>AstNode</c> class. 
		/// </summary>
		/// <param name="textRange">The <see cref="TextRange"/> of the AST node.</param>
		public AstNode(TextRange textRange) : base(textRange) {}
		
		/////////////////////////////////////////////////////////////////////////////////////////////////////
		// PUBLIC PROCEDURES
		/////////////////////////////////////////////////////////////////////////////////////////////////////
		
		/// <summary>
		/// Accepts the specified visitor for visiting this node.
		/// </summary>
		/// <param name="visitor">The visitor to accept.</param>
		/// <remarks>This method is part of the visitor design pattern implementation.</remarks>
		public void Accept(AstVisitor visitor) {
			if (visitor.OnPreVisiting(this))
				this.AcceptCore(visitor);
			visitor.OnPostVisited(this);
		}

		/// <summary>
		/// Accepts the specified visitor for visiting a child node of this node.
		/// </summary>
		/// <param name="visitor">The visitor to accept.</param>
		/// <param name="childNode">The child node to visit.</param>
		/// <remarks>This method is part of the visitor design pattern implementation.</remarks>
		public void AcceptChild(AstVisitor visitor, AstNode childNode) {
			if (childNode != null)
				childNode.Accept(visitor);
		}

		/// <summary>
		/// Accepts the specified visitor for visiting the child nodes of this node.
		/// </summary>
		/// <param name="visitor">The visitor to accept.</param>
		/// <param name="nodeList">The list of child nodes to visit.</param>
		/// <remarks>This method is part of the visitor design pattern implementation.</remarks>
		public void AcceptChildren(AstVisitor visitor, IAstNodeList nodeList) {
			if (nodeList != null) {
				for (int index = 0; index < nodeList.Count; index++) {
					if (nodeList[index] is AstNode)
						((AstNode)nodeList[index]).Accept(visitor);
				}
			}
		}

		/// <summary>
		/// Accepts the specified visitor for visiting this node.
		/// </summary>
		/// <param name="visitor">The visitor to accept.</param>
		/// <remarks>
		/// This method must be implemented by each AST node.  It will look like the following:
		/// <code>
		/// if (visitor.OnVisiting(this)) {
		/// 	// Visit children
		/// 	if (this.ChildNodeCount > 0)
		/// 		this.AcceptChildren(visitor, this.ChildNodes);
		/// }
		/// visitor.OnVisited(this);
		/// </code>
		/// </remarks>
		protected abstract void AcceptCore(AstVisitor visitor);

		/// <summary>
		/// Gets or sets a context value identifying the context of the AST node within its parent node.
		/// </summary>
		/// <remarks>
		/// The context ID value is typically defined on the parent AST node as a constant.
		/// </remarks>
		public override int ContextID { 
				get {
					return contextID;
				}
				set {
					contextID = (byte)value;
				}
			}

		/// <summary>
		/// Gets the <see cref="SimpleNodeType"/> that identifies the type of node.
		/// </summary>
		/// <value>The <see cref="SimpleNodeType"/> that identifies the type of node.</value>
		public abstract SimpleNodeType NodeType { get; }

		/// <summary>
		/// Gets the image index that is applicable for displaying this node in a user interface control.
		/// </summary>
		/// <value>The image index that is applicable for displaying this node in a user interface control.</value>
		public override int ImageIndex {
			get {
				return (int)ActiproSoftware.Products.SyntaxEditor.IconResource.Keyword;
			}
		}

	}

}
